package com.thx.common.service;

import com.thx.common.orm.PropertyDao;
import com.thx.common.orm.PropertyValDao;
import com.thx.common.orm.TemplateDao;
import com.thx.common.orm.model.ExtendPropertyEntity;
import com.thx.common.orm.model.Option;
import com.thx.common.orm.model.Property;
import com.thx.common.orm.model.PropertyVal;
import com.thx.common.orm.model.Template;
import com.thx.common.util.AppContext;
import com.thx.common.util.DateUtil;
import com.thx.common.util.DeepCopyUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 扩展属性组件提供的api，如果在开发中不继承ExtendPropertyManager，调用此api也可以实现.
 * 
 * @author calonlan
 */
@Component
@Transactional(readOnly = true)
public class ExtendPropertyComponent {

  private static final Logger logger = LoggerFactory.getLogger(ExtendPropertyComponent.class);

  @Autowired
  private TemplateDao templateDao;

  @Autowired
  private PropertyDao propertyDao;

  @Autowired
  private PropertyValDao propertyValDao;

  /**
   * 根据实体名称查询模板.
   */
  public Template findTempalteByEntityClass(String entityClassName) {
    // tenantId（租户id）saas模式的租户标识
    String tenantId = AppContext.getCurrentComId();
    List<Template> templates = null;
    if (tenantId == null || tenantId.length() <= 0) {
      // 认为不是saas模式
      templates = templateDao.findByEntityClass(entityClassName);
    } else {
      // saas模式
      templates = templateDao.findByTenantIdAndEntityClass(tenantId, entityClassName);
    }
    Template template = null;
    if (templates != null && templates.size() > 0) {
      template = templates.get(0);
    } else {
      template = new Template();
    }
    return template;
  }

  /**
   * 根据实体名称、实体id查询扩展属性及属性的值.
   */
  public List<Property> findPropertiesByEntityClassAndEntityId(String entityClassName,
      String entityId) {
    Template template = findTempalteByEntityClass(entityClassName);
    return findPropertiesByTemplateIdAndEntityId(template.getId(), entityId);
  }

  /**
   * 根据模板id、实体id查询扩展属性及属性的值.
   */
  public List<Property> findPropertiesByTemplateIdAndEntityId(String templateId, String entityId) {
    List<Property> properties = null;
    if (templateId == null || templateId.length() <= 0) {
      properties = new ArrayList<Property>();
    } else {
      properties = propertyDao.findByTemplateId(templateId);
      for (Property p : properties) {
        List<PropertyVal> vals = propertyValDao.findByPropertyIdAndEntityId(p.getId(), entityId);
        if (vals != null && vals.size() > 0) {
          p.setPropertyVal(vals.get(0));
        } else {
          PropertyVal pv = new PropertyVal();
          pv.setPropertyId(p.getId());
          p.setPropertyVal(pv);
        }
      }
    }
    return properties;
  }

  /**
   * 根据模板id查询扩展属性.
   */
  public List<Property> findPropertiesByTemplateId(String templateId) {
    List<Property> properties = null;
    if (templateId == null || templateId.length() <= 0) {
      properties = new ArrayList<Property>();
    } else {
      properties = propertyDao.findByTemplateId(templateId);
    }
    return properties;
  }

  /**
   * 根据实体类名查询属性.
   */
  public List<Property> findPropertiesByEntityClass(String entityClassName) {
    Template template = findTempalteByEntityClass(entityClassName);
    List<Property> properties = findPropertiesByTemplateId(template.getId());
    return properties;
  }

  /**
   * 根据实体id删除该实体扩展属性的记录.
   */
  public void delPropertyValByEntityId(String entityId) {
    String tenantId = AppContext.getCurrentComId();
    if (tenantId == null || tenantId.length() <= 0) {
      // 认为不是saas模式
      propertyValDao.delByEntityId(entityId);
    } else {
      // saas模式
      propertyValDao.delByTenantIdAndEntity(tenantId, entityId);
    }
  }

  public void savePropertyVal(PropertyVal pv) {
    propertyValDao.saveOrUpdate(pv);
  }

  public void updatePropertyVal(PropertyVal pv) {
    savePropertyVal(pv);

  }

  public Property findPropertyById(String id) {
    return propertyDao.get(id);
  }

  public PropertyVal findPropertyValById(String id) {
    return propertyValDao.get(id);
  }

  /**
   * 把web端传过来的扩展属性数据进行解析(web框架+html)，赋值到实体的标准数据结构中.
   * 
   * @param entity 实体
   * @param entityId 实体id
   * @param paramMap 表单数据map
   */
  @Transactional(readOnly = false)
  public <T extends ExtendPropertyEntity> void setEntityExtendPropertyVals(T entity,
      String entityId, Map<String, String[]> paramMap) {
    List<Property> properties = null;
    if (entityId == null || entityId.length() <= 0) {
      properties = findPropertiesByEntityClass(entity.getClass().getName());
      PropertyVal pv = null;
      for (Property p : properties) {
        String[] vals = paramMap.get(p.getName());
        pv = new PropertyVal();
        pv.setPropertyId(p.getId());
        if (vals != null && vals.length > 0) {
          if ("input-text".equals(p.getShowType())) {
            pv.setStringVal(vals[0]);
          } else if ("input-int".equals(p.getShowType())) {
            if (vals[0] != null && vals[0].length() > 0) {
              pv.setIntVal(Integer.parseInt(vals[0]));
            }
          } else if ("input-float".equals(p.getShowType())) {
            if (vals[0] != null && vals[0].length() > 0) {
              pv.setFloatVal(Float.parseFloat(vals[0]));
            }
          } else if ("radio".equals(p.getShowType())) {
            pv.setStringVal(vals[0]);
          } else if ("select".equals(p.getShowType())) {
            pv.setStringVal(vals[0]);
          } else if ("checkbox".equals(p.getShowType())) {
            String val = "";
            for (String str : vals) {
              val += str + ",";
            }
            val = val.substring(0, val.lastIndexOf(","));
            pv.setStringVal(val);
          } else if ("date".equals(p.getShowType())) {
            try {
              String dateStr = vals[0];
              // Date日期支持两种格式:yyyy-MM-dd和yyyy-MM-dd HH:mm:ss
              if (dateStr.length() == 10) {
                // yyyy-MM-dd
                Date val = DateUtil.parse(dateStr, "yyyy-MM-dd");
                pv.setDateVal(val);
              } else if (dateStr.length() == 19) {
                // yyyy-MM-dd HH:mm:ss
                Date val = DateUtil.parse(dateStr, "yyyy-MM-dd HH:mm:ss");
                pv.setDateVal(val);
              } else {
                throw new ParseException("扩展属性组件:[日期格式不正确或者组件不支持]", 0);
              }
            } catch (ParseException ex) {
              ex.printStackTrace();
            }
          } else if ("textarea".equals(p.getShowType())) {
            pv.setStringVal(vals[0]);
          }
        }
        p.setPropertyVal(pv);
      }
    } else {
      properties = findPropertiesByEntityClassAndEntityId(entity.getClass().getName(), entityId);
      for (Property p : properties) {
        String[] vals = paramMap.get(p.getName());
        if (vals != null && vals.length > 0) {
          if ("input-text".equals(p.getShowType())) {
            p.getPropertyVal().setStringVal(vals[0]);
          } else if ("input-int".equals(p.getShowType())) {
            if (vals[0] != null && vals[0].length() > 0) {
              p.getPropertyVal().setIntVal(Integer.parseInt(vals[0]));
            }
          } else if ("input-float".equals(p.getShowType())) {
            if (vals[0] != null && vals[0].length() > 0) {
              p.getPropertyVal().setFloatVal(Float.parseFloat(vals[0]));
            }
          } else if ("radio".equals(p.getShowType())) {
            p.getPropertyVal().setStringVal(vals[0]);
          } else if ("select".equals(p.getShowType())) {
            p.getPropertyVal().setStringVal(vals[0]);
          } else if ("checkbox".equals(p.getShowType())) {
            String val = "";
            for (String str : vals) {
              val += str + ",";
            }
            val = val.substring(0, val.lastIndexOf(","));
            p.getPropertyVal().setStringVal(val);
          } else if ("date".equals(p.getShowType())) {
            try {
              String dateStr = vals[0];
              // Date日期支持两种格式:yyyy-MM-dd和yyyy-MM-dd HH:mm:ss
              if (dateStr.length() == 10) {
                // yyyy-MM-dd
                Date val = DateUtil.parse(dateStr, "yyyy-MM-dd");
                p.getPropertyVal().setDateVal(val);
              } else if (dateStr.length() == 19) {
                // yyyy-MM-dd HH:mm:ss
                Date val = DateUtil.parse(dateStr, "yyyy-MM-dd HH:mm:ss");
                p.getPropertyVal().setDateVal(val);
              } else {
                throw new ParseException("扩展属性组件:[日期格式不正确或者组件不支持]", 0);
              }
            } catch (ParseException ex) {
              ex.printStackTrace();
            }
          } else if ("textarea".equals(p.getShowType())) {
            p.getPropertyVal().setStringVal(vals[0]);
          }
        } else {

          if ("input-int".equals(p.getShowType())) {
            p.getPropertyVal().setIntVal(null);
          } else if ("input-float".equals(p.getShowType())) {
            p.getPropertyVal().setFloatVal(null);
          } else if ("date".equals(p.getShowType())) {
            p.getPropertyVal().setDateVal(null);
          } else {
            p.getPropertyVal().setStringVal(null);
          }
          /*
           * propertyValDao.delete(p.getPropertyVal().getId()); p.setPropertyVal(new PropertyVal());
           */
        }
      }
    }
    entity.setProperties(properties);
  }

  /**
   * 把web端传过来的扩展属性数据进行解析(rpc+angularjs)，赋值到实体的标准数据结构中.
   * 
   * @param entity 实体
   * @param data 表单数据
   */
  public <T extends ExtendPropertyEntity> void setEntityExtendPropertyVals(T entity,
      List<Option> data) {
    Map<String, String[]> params = new HashMap<String, String[]>();
    for (Option o : data) {
      if (o.getValue().contains(",")) {
        String[] vals = o.getValue().split(",");
        params.put(o.getName(), vals);
      } else {
        String[] vals = {o.getValue()};
        params.put(o.getName(), vals);
      }
    }
    Serializable entityId = entity.getId();
    if (entityId == null) {
      setEntityExtendPropertyVals(entity, null, params);
    } else {
      setEntityExtendPropertyVals(entity, entityId.toString(), params);
    }
  }

  /**
   * 给实体赋值模板、扩展属性及值，一般用于从后端查询数据.
   */
  public <T extends ExtendPropertyEntity> void setExtendPropsAndVals(T entity) {
    if (entity != null) {
      Template template = findTempalteByEntityClass(entity.getClass().getName());
      List<Property> list =
          findPropertiesByTemplateIdAndEntityId(template.getId(), entity.getId().toString());
      entity.setTemplate(template);
      entity.setProperties(list);
    }

  }

  /**
   * 给实体列表赋值模板、扩展属性及值，一般用于从后端查询数据.
   */
  public <T extends ExtendPropertyEntity> void setExtendPropsAndVals(List<T> list) {
    if (list != null && list.size() > 0) {
      Template template = findTempalteByEntityClass(list.get(0).getClass().getName());
      if (template.getId() != null) {
        List<Property> properties = null;
        for (T entity : list) {
          properties =
              findPropertiesByTemplateIdAndEntityId(template.getId(), entity.getId().toString());
          try {
            // 深度复制properties，否则每个实体对象的properties都是一样的
            properties = DeepCopyUtil.deepCopy(properties);
          } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
          } catch (IOException ex) {
            ex.printStackTrace();
          }
          entity.setProperties(properties);
          entity.setTemplate(template);
        }
      }
    }
  }

}
